/**
 * 
 */
package platzerworld.kegeln.db.verein;

import java.util.ArrayList;
import java.util.List;

import platzerworld.kegeln.common.db.Sortierung;
import platzerworld.kegeln.common.logging.LOG;
import platzerworld.kegeln.db.KegelverwaltungDatenbank;
import platzerworld.kegeln.db.klasse.KlasseTbl;
import platzerworld.kegeln.db.mannschaft.MannschaftTbl;
import platzerworld.kegeln.vo.klasse.KlasseVO;
import platzerworld.kegeln.vo.verein.VereinVO;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.util.Log;

/**
 * Der VereinSpeicher ist die Schnittstelle zu persistenten Vereindaten.
 * 
 */
public class VereinSpeicher {

	/** Markierung für Logging. */
	private static final String TAG = "SpielerSpeicher";
	
	/** Verweis auf die Kegelverwaltung-Datenbank. */
	private KegelverwaltungDatenbank mDb;

	/**
	 * Erzeugt einen neuen Vereinspeicher.
	 * Dabei wird sichergestellt, dass die zugrundeliegende Datenbankunmittelbar nutzbar ist.
	 * 
	 * @param context Kontext der Anwendung, für die der Speicher gültig sein soll.
	 */
	public VereinSpeicher(Context context) {
		mDb = new KegelverwaltungDatenbank(context);
		oeffnen();
		LOG.v(TAG, "Vereinspeicher angelegt.");
	}

	/**
	 * Erzeugung ohne Context nicht möglich.
	 */
	private VereinSpeicher() {
	}

	/**
	 * Speichert einen Verein. Ist dieser bereits in der Datenbank bekannt, wird der vorhandene Datensatz geändert.
	 * Ansonsten wird ein neuer Datensatz erzeugt.
	 * 
	 * @param vereinVO Value-Object Verein
	 * 
	 * @return id des persistenten Vereins.
	 * 
	 */
	public long speichereVerein(VereinVO vereinVO) {
		if (vereinVO.istNeu()) {
			return speichereVereinAllColumns(vereinVO);
		} else {
			aendereVerein(vereinVO);
			return vereinVO.key;
		}
	}
	
	/**
	 * Legt einen neuen Verein in der Datenbank an.
	 * 
	 * @param vereinVO enthält die Daten des Vereins
	 * 
	 * @return key Verein
	 */
	public long speichereVereinAllColumns(VereinVO vereinVO) {
		final ContentValues daten = new ContentValues();
		daten.put(VereinTbl.NAME, vereinVO.name);
		daten.put(VereinTbl.CLUB_NUMMER, vereinVO.clubnummer);
		daten.put(VereinTbl.CLUB, vereinVO.club);

		final SQLiteDatabase dbCon = mDb.getWritableDatabase();

		try {
			final long id = dbCon.insertOrThrow(VereinTbl.TABLE_NAME, null, daten);
			Log.i(TAG, "Verein mit id=" + id + " erzeugt.");
			return id;
		} finally {
			dbCon.close();
		}
	}

	/**
	 * Ändert einen vorhandenen Verein in der Datenbank. 
	 * Wenn die id nicht mitgegeben wird, wird keine Änderung durchgeführt. 
	 * Es werden bei der Änderung alle Parameter berücksichtigt.
	 * 
	 * @param vereinVO enthält die Daten des Vereins
	 */
	public void aendereVerein(VereinVO vereinVO) {
		if (vereinVO.key == 0) {
			Log.w(TAG, "id == 0 => kein update möglich.");
			return;
		}

		final ContentValues daten = new ContentValues();
		daten.put(VereinTbl.NAME, vereinVO.name);
		daten.put(VereinTbl.CLUB_NUMMER, vereinVO.clubnummer);
		daten.put(VereinTbl.CLUB, vereinVO.club);

		final SQLiteDatabase dbCon = mDb.getWritableDatabase();

		try {
			dbCon.update(VereinTbl.TABLE_NAME, daten, VereinTbl.WHERE_ID_EQUALS, new String[] { String.valueOf(vereinVO.key) });
			Log.i(TAG, "Verein id=" + vereinVO.key + " aktualisiert.");
		} finally {
			dbCon.close();
		}
	}

	/**
	 * Entfernt einen Verein aus der Datenbank.
	 * 
	 * @param id Schlüssel des gesuchten Vereins
	 * 
	 * @return true, wenn Datensatz geloescht wurde.
	 */
	public boolean loescheVerein(long id) {
		final SQLiteDatabase dbCon = mDb.getWritableDatabase();

		int anzahlLoeschungen = 0;
		try {
			anzahlLoeschungen = dbCon.delete(VereinTbl.TABLE_NAME, VereinTbl.WHERE_ID_EQUALS,
					new String[] { String.valueOf(id) });
			Log.i(TAG, "Verein id=" + id + " gelöscht.");
		} finally {
			dbCon.close();
		}
		return anzahlLoeschungen == 1;
	}
	/**
	 * Liefert alle Klassen sortiert nach NAME zurück. 
	 * Es kann (optional) ein Filterkriterium angegeben werden. 
	 * Wenn der namensFilter definiert ist, werden nur Klassen geliefert, deren NAME mit diesem Buchstaben beginnt.
	 * 
	 * @return Cursor auf die Klassenliste.
	 */
	public List<VereinVO> ladeAlleVereineListeVO() {
		return ladeVereineListeVO(Sortierung.STANDARD, null);
	}
	
	/**
	 * Liefert alle Klassen mit einstellbarer Sortierung zurück. 
	 * Es kann (optional) ein Filterkriterium angegeben werden. 
	 * Wenn der namensFilter definiert ist, werden nur Klassen geliefert, deren NAME mit diesem Buchstaben beginnt.
	 * 
	 * @param sortierung Art der Sortierung
	 * @param namensFilter Anfangsbuchstaben (case sensitive) der zu suchenden Kontakte.
	 * @return Cursor auf die Klassenliste.
	 */
	public List<VereinVO> ladeVereineListeVO(Sortierung sortierung, CharSequence namensFilter) {
		try{
			final SQLiteQueryBuilder vereineSuche = new SQLiteQueryBuilder();
			vereineSuche.setTables(VereinTbl.TABLE_NAME);
			String[] whereAttribs = null;
			
			Cursor klassenCursor = vereineSuche.query(mDb.getReadableDatabase(), VereinTbl.ALL_COLUMNS, null, whereAttribs, null, null,
					getVereinSortierung(sortierung));
			
			
			return ladeVereineKeyValueVO(klassenCursor);
		}finally{
			schliessen();
		}
	}
	
	/**
	 * Lädt die Klassen aus dem KlasseTbl-Datensatz, auf dem der Cursor gerade steht.
	 * 
	 * Der Cursor wird anschließend deaktiviert, da er im KlasseSpeicher nur intern als "letzter Aufruf" aufgerufen wird.
	 * 
	 * @param c aktuelle Cursorposition != null
	 * @return Exemplar von Klasse.
	 */
	public ArrayList<VereinVO> ladeVereineKeyValueVO(Cursor c) {	
		ArrayList<VereinVO> vereinVOs = new ArrayList<VereinVO>();
		VereinVO vereinVO = null;
		if (c != null ) {
    		if  (c.moveToFirst()) {
    			do {    				
    				vereinVO = new VereinVO(
    						c.getLong(c.getColumnIndex(VereinTbl.ID)), 
    						c.getString(c.getColumnIndex(VereinTbl.NAME)), 
    						c.getInt(c.getColumnIndex(VereinTbl.CLUB_NUMMER)),
    						c.getString(c.getColumnIndex(VereinTbl.CLUB)));
    				
    				vereinVOs.add(vereinVO);
    			}while (c.moveToNext());
    		} 
    	}

		return vereinVOs;
	}

	/**
	 * Liefert einen Cursor zur ID auf alle Felder der Verein-Tabelle zurück.
	 * 
	 * @param id der Key des Vereins
	 * 
	 * @return Cursor, oder null
	 */
	public Cursor ladeVereinDetails(long id) {
		return mDb.getReadableDatabase().query(VereinTbl.TABLE_NAME, VereinTbl.ALL_COLUMNS, VereinTbl.WHERE_ID_EQUALS,
				new String[] { String.valueOf(id) }, null, null, null);
	}

	/**
	 * Liefert ein Value-Object VereinVO zur id mit allen Feldern der Verein-Tabelle zurück.
	 * 
	 * @param id Schüssel des gesuchten Vereins
	 * 
	 * @return VereinVO, oder null
	 */
	public VereinVO ladeVerein(long id) {
		VereinVO kontakt = null;
		Cursor c = null;
		try {
			c = mDb.getReadableDatabase().query(VereinTbl.TABLE_NAME, VereinTbl.ALL_COLUMNS, VereinTbl.WHERE_ID_EQUALS,
					new String[] { String.valueOf(id) }, null, null, null);
			if (c.moveToFirst() == false) {
				return null;
			}
			kontakt = ladeVerein(c);
		} finally {
			if (c != null) {
				c.close();
			}
		}
		return kontakt;
	}

	/**
	 * Liefert einen Cursor zum Name auf alle Felder der Verein-Tabelle zurück.
	 * 
	 * @param name der Vereinsname
	 * 
	 * @return Cursor, oder null
	 */
	public Cursor ladeVereinDetails(String name) {
		if (name == null) {
			return null;
		}
		return mDb.getReadableDatabase().query(VereinTbl.TABLE_NAME, VereinTbl.ALL_COLUMNS, VereinTbl.WHERE_NAME_EQUALS,
				new String[] { name }, null, null, VereinTbl.ORDER_BY_NAME);
	}

	/**
	 * Liefert alle VereinVO's sortiert nach Name zurück.
	 * 
	 * Es kann (optional) ein Filterkriterium angegeben werden. 
	 * Wenn dernamensFilterdefiniert ist, werden nur Vereine geliefert, deren NAME mit diesem Buchstaben beginnt.
	 * 
	 * @param namensFilter Anfangsbuchstaben (case sensitive) des zu suchenden Vereins.
	 * 
	 * @return Cursor auf die Ergebnisliste.
	 */
	public Cursor ladeVereinListe(CharSequence namensFilter) {
		return ladeVereinListe(Sortierung.STANDARD, namensFilter);
	}
	
	/**
	 * Lädt die Vereine aus dem VereinTbl-Datensatz, auf dem der Cursor gerade steht.
	 * Der Cursor wird anschließend deaktiviert, da er im Vereinpeicher nur intern als "letzter Aufruf" aufgerufen wird.
	 * 
	 * @return List<String[]> vereine als String-Array
	 */
	public List<String[]> ladeVereinAsStringArray() {	
		Cursor c = ladeVereinListe(null);
		
		List<String[]> vereinAsArray = new ArrayList<String[]>();
		if (c != null ) {
    		if  (c.moveToFirst()) {
    			do { 
    				String[] vereinZeile = new String[6];
    				vereinZeile[0] = String.valueOf(c.getInt(c.getColumnIndex(VereinTbl.ID)));
    				vereinZeile[1] = c.getString(c.getColumnIndex(VereinTbl.NAME));
    				vereinZeile[2] = String.valueOf(c.getInt(c.getColumnIndex(VereinTbl.CLUB_NUMMER)));
    				vereinZeile[3] = c.getString(c.getColumnIndex(VereinTbl.CLUB));
    				vereinZeile[4] = c.getString(c.getColumnIndex(VereinTbl.LOC_LONGITUDE));
    				vereinZeile[5] = c.getString(c.getColumnIndex(VereinTbl.LOC_LATITUDE));
    				vereinAsArray.add(vereinZeile);
    			}while (c.moveToNext());
    		} 
    	}

		return vereinAsArray;
	}

	/**
	 * Liefert alle Vereine mit einstellbarer Sortierung zurück.
	 * Es kann (optional) ein Filterkriterium angegeben werden. Wenn der namensFilter definiert ist.
	 * 
	 * @param sortierung  Art der Sortierung
	 * @return Cursor auf die Ergebnisliste.
	 */
	public Cursor ladeVereinListe(Sortierung sortierung, CharSequence namensFilter) {
		final SQLiteQueryBuilder vereineSuche = new SQLiteQueryBuilder();
		vereineSuche.setTables(VereinTbl.TABLE_NAME);
		String[] whereAttribs = null;
		if (namensFilter != null && namensFilter.length() > 0) {
			vereineSuche.appendWhere(VereinTbl.WHERE_NAME_LIKE);
			whereAttribs = new String[] { namensFilter + "%" };
		}

		return vereineSuche.query(mDb.getReadableDatabase(), VereinTbl.ALL_COLUMNS, null, whereAttribs, null, null,
				getVereinSortierung(sortierung));
	}

	/**
	 * Liefert die Sortierung unter Berücksichtigung der Standard-Sortierung der Vereintabelle.
	 * 
	 * @param sortierung Sortierung als enum.
	 * 
	 * @return Sortierung als ORDER_BY kompatible Anweisung.
	 */
	private static String getVereinSortierung(Sortierung sortierung) {
		String sortiertNach = VereinTbl.DEFAULT_SORT_ORDER;
		switch (sortierung) {
		case NAME:
			sortiertNach = VereinTbl.NAME;
			break;
		default:
			break;
		}
		return sortiertNach;
	}

	/**
	 * Lädt den Verein aus dem VereinTbl-Datensatz, auf dem der Cursor gerade steht.
	 * Der Cursor wird anschließend deaktiviert, da er im VereinSpeicher nur intern als "letzter Aufruf" aufgerufen wird.
	 * 
	 * @param c aktuelle Cursorposition != null
	 * 
	 * @return VereinVO, oder null
	 */
	public VereinVO ladeVerein(Cursor c) {
		final VereinVO vereinVO = new VereinVO();

		vereinVO.key = c.getLong(c.getColumnIndex(VereinTbl.ID));
		vereinVO.name = c.getString(c.getColumnIndex(VereinTbl.NAME));
		vereinVO.clubnummer = c.getInt(c.getColumnIndex(VereinTbl.CLUB_NUMMER));
		vereinVO.club = c.getString(c.getColumnIndex(VereinTbl.CLUB));
		return vereinVO;
	}

	/**
	 * Schliesst die zugrundeliegende Datenbank. Vor dem naechsten Zugriff muss oeffnen() aufgerufen werden.
	 */
	public void schliessen() {
		mDb.close();
		LOG.v(TAG, "Datenbank kegelverwaltung geschlossen.");
	}

	/**
	 * Oeffnet die Datenbank, falls sie vorher mit schliessen() geschlossen wurde.
	 * Bei Bedarf wird das Schema angelegt bzw. aktualisiert.
	 */
	public void oeffnen() {
		mDb.getReadableDatabase();
		LOG.v(TAG, "Datenbank kegelverwaltung geoeffnet.");
	}

	/**
	 * Gibt die Anzahl der Vereine in der Datenbank zurueck.
	 * Performanter als Cursor::getCount.
	 * 
	 * @return Anzahl der Vereine.
	 */
	public int anzahlVereine() {
		final Cursor c = mDb.getReadableDatabase().rawQuery("select count(*) from " + VereinTbl.TABLE_NAME, null);
		if (c.moveToFirst() == false) {
			return 0;
		}
		return c.getInt(0);
	}

}
